﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using Microsoft.Xrm.Sdk;

namespace WebResourcesManager.AppCode
{
    class TreeViewHelper
    {
        #region Folders and TreeNodes methods

        /// <summary>
        /// Create an item (script file or folder) on disk depending on specifed
        /// TreeNode
        /// </summary>
        /// <param name="node">TreeNode element</param>
        /// <param name="folderPath">Current physical path</param>
        public static void CreateItem(TreeNode node, string folderPath)
        {
            // If current node has child, it is a folder, not a script
            if (node.Nodes.Count > 0)
            {
                bool doContinue = false;

                // Check if current node has child nodes checked. If not, no need
                // to create a folder on disk
                foreach (TreeNode childNode in node.Nodes)
                {
                    if (childNode.Checked)
                    {
                        doContinue = true;
                        break;
                    }
                }

                if (doContinue)
                {
                    Directory.CreateDirectory(folderPath + "\\" + node.Text);

                    foreach (TreeNode childNode in node.Nodes)
                    {
                        if (node.Checked)
                        {
                            CreateItem(childNode, folderPath + "\\" + node.Text);
                        }
                    }
                }
            }
            else
            {
                // If checked, create a script file on disk
                if (node.Checked)
                {
                    Entity webResource = ((WebResource)node.Tag).WebResourceEntity;

                    using (StreamWriter writer = new StreamWriter(folderPath + "\\" + node.Text, false))
                    {
                        if (webResource.Contains("content"))
                            writer.Write(WebResourceManager.GetContentFromBase64String(webResource["content"].ToString()));
                        else
                            writer.WriteLine(string.Empty);
                    }
                }
            }
        }

        /// <summary>
        /// Create a TreeView folder structure depending on the DirectoryInfo
        /// element in parameters
        /// </summary>
        /// <param name="parentFolderNode">Current TreeNode</param>
        /// <param name="di">Current physical directory info</param>
        public static void CreateFolderStructure(TreeNode parentFolderNode, DirectoryInfo di)
        {
            foreach (DirectoryInfo diChild in di.GetDirectories())
            {
                // If the current physical directory has sub directories or 
                // javascript file, a new TreeNode has to be created
                if (diChild.GetDirectories().Length > 0 || diChild.GetFiles("*.*").Length > 0)
                {
                    TreeNode folderNode = new TreeNode(diChild.Name);
                    folderNode.ImageIndex = 1;
                    folderNode.SelectedImageIndex = 1;

                    parentFolderNode.Nodes.Add(folderNode);

                    CreateFolderStructure(folderNode, diChild);
                }
            }

            foreach (FileInfo fiChild in di.GetFiles("*.*", SearchOption.TopDirectoryOnly))
            {
                // Create a TreeNode for each javascript file
                CreateWebResourceNode(fiChild, parentFolderNode);
            }
        }

        /// <summary>
        /// Create a TreeNode for the javascript file passed in parameter
        /// </summary>
        /// <param name="fiChild">Javascript FileInfo</param>
        /// <param name="parent">Parent element (TreeView or TreeNode)</param>
        public static void CreateWebResourceNode(FileInfo fiChild, object parent)
        {
            string scriptId = string.Empty;
            string scriptName = fiChild.Name;
            string fileName = scriptName;

            // Creating the script "name" attribute which depends on the current
            // TreeView structure
            if (parent is TreeNode)
            {
                TreeNode parentNode = (TreeNode)parent;

                while (parentNode != null && !parentNode.Text.EndsWith("_"))
                {
                    fileName = parentNode.Text + "/" + fileName;
                    parentNode = parentNode.Parent;
                }

                fileName = parentNode.Text + "/" + fileName;
            }

            int imageIndex = 0;

            switch (fiChild.Extension.ToLower().Remove(0, 1))
            {
                case "html":
                case "htm":
                    imageIndex = 2;
                    break;
                case "css":
                    imageIndex = 3;
                    break;
                case "js":
                    imageIndex = 4;
                    break;
                case "png":
                    imageIndex = 6;
                    break;
                case "jpg":
                    imageIndex = 7;
                    break;
                case "gif":
                    imageIndex = 8;
                    break;
                case "xap":
                    imageIndex = 9;
                    break;
                case "xsl":
                    imageIndex = 10;
                    break;
                case "ico":
                    imageIndex = 11;
                    break;
            }


            // Create new virtual web resource
            Entity script = new Entity("webresource");
            script["name"] = fileName;
            script["webresourcetype"] = new OptionSetValue(imageIndex - 1);

            // Add content
            script["content"] = Convert.ToBase64String(File.ReadAllBytes(fiChild.FullName));

            WebResource scriptObject = new WebResource(script, fiChild.FullName);

            TreeNode node = new TreeNode()
            {
                Text = scriptName,
                Tag = scriptObject,
                ImageIndex = imageIndex,
                SelectedImageIndex = imageIndex
            };


            


            if (parent is TreeNode)
            {
                ((TreeNode)parent).Nodes.Add(node);
            }
            else
            {
                ((TreeView)parent).Nodes.Add(node);
            }
        }

        #endregion Folders and TreeNodes methods

        /// <summary>
        /// Propagate the current node checked state to the child nodes
        /// </summary>
        /// <param name="node">Current TreeNode</param>
        /// <param name="status">Checked state</param>
        public static void ChangeChildNodeCheckStatus(TreeNode node, bool status)
        {
            node.Checked = status;

            foreach (TreeNode childNode in node.Nodes)
            {
                ChangeChildNodeCheckStatus(childNode, status);
            }
        }

        /// <summary>
        /// Propagate current node checked state to its parent node
        /// </summary>
        /// <param name="node">Current TreeNode</param>
        /// <param name="status">Checked state</param>
        public static void ChangeParentNodeCheckStatus(TreeNode node, bool status)
        {
            node.Checked = status;

            if (node.Parent != null)
            {
                int childNodesCheckedCount = 0;
                childNodesCheckedCount = CountCheckNodes(node.Parent, childNodesCheckedCount);

                if (status == false)
                {
                    if (childNodesCheckedCount == 1)
                    {
                        node.Parent.Checked = false;
                        ChangeParentNodeCheckStatus(node.Parent, status);
                    }
                }
                else
                {
                    node.Parent.Checked = true;
                    ChangeParentNodeCheckStatus(node.Parent, status);
                }
            }
        }

        /// <summary>
        /// Counts the number of checked TreeNodes
        /// </summary>
        /// <param name="node">Current TreeNode</param>
        /// <param name="count">Number of checked TreeNodes</param>
        /// <returns>Number of checked TreeNodes updated</returns>
        public static int CountCheckNodes(TreeNode node, int count)
        {
            if (node.Checked)
                count++;

            foreach (TreeNode childNode in node.Nodes)
                count = CountCheckNodes(childNode, count);

            return count;
        }

        internal static void GetNodes(List<TreeNode> nodes, object o, bool onlyCheckedNodes)
        {
            if (o is TreeView)
            {
                foreach (TreeNode node in ((TreeView)o).Nodes)
                {
                    if (onlyCheckedNodes && node.Checked || !onlyCheckedNodes)
                        if (node.Tag != null)
                        {
                            string name = GetName(node);
                            ((WebResource)node.Tag).WebResourceEntity["name"] = name;

                            nodes.Add(node);
                        }

                    GetNodes(nodes, node, onlyCheckedNodes);
                }
            }
            else
            {
                foreach (TreeNode node in ((TreeNode)o).Nodes)
                {
                    if (onlyCheckedNodes && node.Checked || !onlyCheckedNodes)
                        if (node.Tag != null)
                        {
                            string name = GetName(node);
                            ((WebResource)node.Tag).WebResourceEntity["name"] = name;

                            nodes.Add(node);
                        }

                    GetNodes(nodes, node, onlyCheckedNodes);
                }
            }
        }

        private static string GetName(TreeNode node)
        {
            string name = node.Text;

            while (node.Parent != null)
            {
                node = node.Parent;
                name = string.Format("{0}/{1}", node.Text, name);
            }

            return name;
        }
    }
}
